#include "standarditemmodel.h"
#include <QJsonDocument>
#include <QDebug>

StandardItemModel::StandardItemModel(QObject *parent): QStandardItemModel(parent)
{

}

QModelIndex StandardItemModel::appendRow(const QModelIndex &index, const QVariantMap &data)
{
    QStandardItem * item = this->itemFromIndex(index);
    QModelIndex nIndex;

    if (!item) {
        nIndex = this->append(this->invisibleRootItem(), data);
    }
    else {
        nIndex = this->append(item->parent(), data);
    }

    return nIndex;
}

void StandardItemModel::appendRows(const QModelIndex &index, const QVariantList &list)
{
    foreach (QVariant data, list) {
      this-> appendRow(index, data.toMap());
    }
}

void StandardItemModel::appendChildren(const QModelIndex &index, const QVariantList &list)
{
    foreach (QVariant data, list) {
      this-> appendChild(index, data.toMap());
    }
}

QModelIndex StandardItemModel::appendChild(const QModelIndex &index, const QVariantMap &data)
{
    QStandardItem * item = this->itemFromIndex(index);

    if (!item)
        return QModelIndex();

    return this->append(item, (data));
}

void StandardItemModel::removeRow(const QModelIndex &index)
{
    QStandardItemModel::removeRow(index.row(), index.parent());
}

void StandardItemModel::insertRow(int row, const QVariantMap &map, const QModelIndex &index)
{
    QStandardItem * parent = this->itemFromIndex(index);

    if (!parent) return;

    //QVariantMap map = data;

    if (!map.contains("display"))
        return;

    QStandardItem *item = new QStandardItem(map.value("display").toString());

    QHash<int, QByteArray> d  = this->roleNames();
    QHashIterator<int, QByteArray> itor = d;
    while (itor.hasNext()) {
        itor.next();
        if (map.contains(itor.value())) {
            item->setData(map.value(itor.value()), itor.key());
        }
    }

    parent->insertRow(row, item);

    QVariantList list = map.value("next").toList();

    if (!list.isEmpty()) {
        this->loop(item, list);
    }
}

QVariant StandardItemModel::itemData(const QModelIndex &index, const QString &name) const
{
    QHash<int, QByteArray> d  = this->roleNames();

    int role = d.key(name.toLatin1());

#ifdef QT_DEBUG
    qInfo() << "role:" << role << ", name: " << name << ", display:" << this->data(index);
#endif
    return this->data(index, role);
}

void StandardItemModel::setItemData(const QModelIndex &index, const QVariant &value, const QString &name)
{
    QHash<int, QByteArray> d  = this->roleNames();

    int role = d.key(name.toLatin1());

    this->setData(index, value, role);
}

QVariantList StandardItemModel::treeData()
{
    QStandardItem * item = this->invisibleRootItem();

    QVariantList list;

    this->exported(item, list);

    return list;
}

int StandardItemModel::level(const QModelIndex &index)
{
    QStandardItem *parent = this->itemFromIndex(index);

    int nlevel = -1;

    while(parent) {
        nlevel++;
        parent = parent->parent();
    }

    return nlevel;
}

QVariantList StandardItemModel::pathData(const QModelIndex &index)
{
    QStandardItem * item = this->itemFromIndex(index);

    QStandardItem *parent = 0;

    QVariantList list;

    if (item) {
        QVariantMap map;

        map.insert("display", item->text());
        map.insert("property", item->data(this->role("property")));

        list.append(map);

        parent = item->parent();

        while(parent) {
            map.clear();

            map.insert("display", parent->text());
            map.insert("property", parent->data(this->role("property")));


            parent = parent->parent();

            list.append(map);
        }
    }
    return list;
}

void StandardItemModel::clear()
{
    QStandardItemModel::clear();
}

QModelIndex StandardItemModel::parent(const QModelIndex &index)
{
    return QStandardItemModel::parent(index);
}

bool StandardItemModel::hasParent(const QModelIndex &index)
{
    return index.parent().isValid();
}

bool StandardItemModel::hasChildren(const QModelIndex &index) const
{
    QStandardItem * item = this->itemFromIndex(index);

    if (item && item->hasChildren())
        return true;
    return false;
}

QModelIndex StandardItemModel::index(int row, const QModelIndex &parent) const
{
    return QStandardItemModel::index(row, 0, parent);
}

QModelIndex StandardItemModel::siblingIndex(int row, const QModelIndex &index) const
{
    return this->sibling(row, 0, index);
}

int StandardItemModel::rowCount(const QModelIndex &parent) const
{
    return QStandardItemModel::rowCount(parent);
}
bool StandardItemModel::moveUp(const QModelIndex &index)
{
    return this->moveRow(index.parent(), index.row(), index.parent(), index.row() - 1);
}

bool StandardItemModel::moveDown(const QModelIndex &index)
{    
    return this->moveRow(index.parent(), index.row(), index.parent(), index.row() + 1);
}

QHash<int, QByteArray> StandardItemModel::roleNames() const
{
    QHash<int, QByteArray> names = QStandardItemModel::roleNames();
    names.insert(Qt::UserRole + 1, "property");
    return names;
}

bool StandardItemModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
{
    if(sourceRow < 0 || sourceRow >= this->rowCount(sourceParent))
        return false;

    if(destinationChild < 0 || destinationChild >= this->rowCount(destinationParent))
        return false;
    if(sourceRow == destinationChild)
        return false;

    if (sourceRow == destinationChild)
        return false;

    qDebug() << (sourceParent == destinationParent);

    int sourceLast = sourceRow + count - 1;
    QStandardItem * item = this->itemFromIndex(destinationParent);

    if (!item)
        item = this->invisibleRootItem();



    QStandardItem *source = this->itemFromIndex(sourceParent);
    if (!source)
        source = this->invisibleRootItem();

    int dest = destinationChild + (sourceRow < destinationChild ? 2 : 0);

    Q_ASSERT(dest >= 0);


    for (int i = 0; i < count; i++) {
        QList<QStandardItem *> items = source->takeRow(sourceRow + i);

        item->insertRows(destinationChild, items);
    }



    return true;
}

QModelIndex StandardItemModel::append(QStandardItem *parent, const QVariantMap &data)
{
    if (!parent)
        parent = this->invisibleRootItem();

    if (!data.contains("display"))
        return QModelIndex();

    QStandardItem *item = new QStandardItem(data.value("display").toString());

    if (data.contains("property")) {
        item->setData(data.value("property"), this->role("property"));
    }

    parent->appendRow(item);

    return item->index();
}

void StandardItemModel::loop(QStandardItem *parent, const QVariantList &data)
{
    if (!parent)
        parent = this->invisibleRootItem();

    foreach (QVariant k, data) {
        QVariantMap map = k.toMap();

        if (!map.contains("display"))
            continue;

        QStandardItem *item = new QStandardItem(map.value("display").toString());

        QHash<int, QByteArray> d  = this->roleNames();
        QHashIterator<int, QByteArray> itor = d;

        while (itor.hasNext()) {
            itor.next();

            if (map.contains(itor.value())) {
                item->setData(map.value(itor.value()), itor.key());
            }
        }

        parent->appendRow(item);


        QVariantList list = map.value("next").toList();

        if (!list.isEmpty()) {
            this->loop(item, list);
        }
    }
}

void StandardItemModel::exported(QStandardItem * item, QVariantList &list)
{
    int rows = item->rowCount();

    for (int i = 0; i < rows; i++) {
        QStandardItem *c = item->child(i);

        QVariantMap data;
        data.insert("display", c->text());

        QHash<int, QByteArray> d  = this->roleNames();
        QHashIterator<int, QByteArray> itor = d;
        while (itor.hasNext()) {
            itor.next();
            data.insert(itor.value(), c->data(itor.key()));
        }

        if (c->hasChildren()) {
            QVariantList next;

            exported(c, next);

            data.insert("next", next);
        }

        list.append(data);
    }
}

int StandardItemModel::role(const QString &name)
{
    QHash<int, QByteArray> d  = this->roleNames();

    return d.key(name.toLocal8Bit());
}
